import { AmbientLight,AxesHelper, BoxGeometry, Color, DirectionalLight, Mesh, MeshPhysicalMaterial, PerspectiveCamera, Scene, Texture, Vector3, WebGLRenderer } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

interface sceneParams {
    canvas?:HTMLCanvasElement,
    antialias?:boolean,
    alpha?:boolean,
    cameraPosition?:Vector3,
    directLight?:number,
    ambientLight?:number,
    background?:Color|Texture,
    aixs?:number, 
    cube?:boolean,
}
const defaultParams:sceneParams={
    antialias:true,
    cameraPosition:new Vector3(0,5,30),
}
export interface Stage {
    scene: Scene;
    camera: PerspectiveCamera;
    renderer: WebGLRenderer;
    resize: () => boolean;
    controls: OrbitControls;
    loopRender: () => void;
    beforeRender: () => void;
    afterRender: () => void;
    destroy: () => void;
}
export function initScene(params:sceneParams ={}) {
    params = { ...defaultParams, ...params };
    const scene = new Scene(), dl = new DirectionalLight(0xffffff,params.directLight),al = new AmbientLight(0xffffff,params.ambientLight);
    const camera = new PerspectiveCamera(50,1,0.1,1000);
    if( params.cameraPosition ) camera.position.copy(params.cameraPosition);
    if( params.aixs ) {
        const axisHelper = new AxesHelper( params.aixs );
        scene.add( axisHelper ); 
    }
    if( params.background ) {
        scene.background = params.background; 
    }
    dl.position.copy(camera.position);

    if( params.directLight ) scene.add(dl);
    if( params.ambientLight ) scene.add(al);
    if( params.cube ) scene.add(new Mesh(new BoxGeometry(2,2,2),new MeshPhysicalMaterial({color:0xff9900})));

    const renderer = new WebGLRenderer({
        canvas:params.canvas,
        antialias:params.antialias,
        alpha:params.alpha,
    });
    function resize() {
        const canvas = renderer.domElement;
        const dpr = Math.max(2,window.devicePixelRatio) ;
        const width = canvas.clientWidth *dpr;
        const height = canvas.clientHeight *dpr;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
            renderer.setSize(width, height, false);
        }
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        return needResize;
    }    
    window.addEventListener('resize', () => {
        resize();
    });
    const controls  = new OrbitControls(camera,renderer.domElement);
    let frameID = 1;
    const stage = {
        scene,camera,renderer,resize,controls,loopRender,
        beforeRender:()=>{},
        afterRender:()=>{},
        destroy:()=>{
            cancelAnimationFrame(frameID);
            renderer.dispose();// 这方法要先执行才不会引起报错，
            renderer.domElement.remove();
            requestIdleCallback(()=>{  
                renderer.forceContextLoss();
            })
         }
    }
    function loopRender() {
        stage.beforeRender && stage.beforeRender();
        renderer.render(scene, camera);
        frameID = requestAnimationFrame(loopRender);
        stage.afterRender && stage.afterRender();
    }

    return stage;
}